import { defineStore } from "pinia";
import { ref, reactive } from "vue";
import { Terminal } from "xterm";
import { FitAddon } from "xterm-addon-fit";
import "xterm/css/xterm.css";
import "xterm/lib/xterm.js";
import { message } from "~/utils/utils.js";
const useWebShell = defineStore("webshell", () => {
  const termID = ref("");

  //   设置要绑定的id
  const setTermID = (id = "term") => {
    termID.value = id;
  };

  const webshellMap = reactive({});

  const initTerm = (instanceID) => {
    const data = reactive({
      term: null,
      socket: null,
    });
    if (termID.value == "") {
      setTermID();
    }
    data.term = new Terminal({
      rendererType: "canvas", //渲染类型
      rows: 30, //行数
      cols: 120,
      convertEol: false, //启用时，光标将设置为下一行的开头
      scrollback: 10, //终端中的回滚量
      disableStdin: false, //是否应禁用输入
      cursorStyle: "underline", //光标样式
      cursorBlink: true, //光标闪烁
      theme: {
        foreground: "white", //字体
        background: "#060101", //背景色
        cursor: "help", //设置光标
      },
    });

    data.term.open(document.getElementById(termID.value));
    // data.term.open(document.querySelector(`.${termID.value}`));
    data.term.writeln("Connecting...");
    data.term.clear();
    //终端适应父元素大小
    const fitAddon = new FitAddon();
    data.term.loadAddon(fitAddon);
    fitAddon.fit();
    //获取终端的焦点
    data.term.focus();
    let _data = data; //一定要重新定义一个this，不然this指向会出问题
    //onData方法用于定义输入的动作
    data.term.onData(function (key) {
      // 这里key值是输入的值，数据格式就是后端定义的 {"operation":"stdin","data":"ls"}
      let msgOrder = {
        operation: "stdin",
        data: key,
      };
      //发送数据
      _data.socket.send(JSON.stringify(msgOrder));
    });

    data.term.onResize((size) => {
      const resize = JSON.stringify({
        operation: "resize",
        cols: size.cols,
        rows: size.rows,
      });
      data.socket.send(resize);
    });

    webshellMap[instanceID] = data;
    // window.addEventListener("resize", fitListener);
  };

  const fitPlugin = new FitAddon();
  const fitListener = () => {
    fitPlugin.fit();
  };

  const initSocket = (instanceID) => {
    const url = `ws://127.0.0.1:6180/api/cmdb/webshell?instanceID=${instanceID}`;

    if (webshellMap[instanceID].socket !== null || url == "") {
      return;
    }

    //定义websocket连接地址
    let terminalWsUrl = url;

    //实例化
    webshellMap[instanceID].socket = new WebSocket(terminalWsUrl);

    let socket = webshellMap[instanceID].socket;
    let term = webshellMap[instanceID].term;
    //关闭连接时的方法
    socketOnClose(socket, term);
    //接收消息的方法
    socketOnMessage(socket, term);
    //报错时的方法
    socketOnError(socket, term);
    console.table(webshellMap);
  };

  const socketOnMessage = (socket, term) => {
    socket.onmessage = (msg) => {
      //接收到消息后将字符串转为对象，输出data内容
      let content = JSON.parse(msg.data);
      term.write(content.data);
    };
  };
  const socketOnClose = (socket, term) => {
    socket.onclose = () => {
      //关闭连接后打印在终端里
      socket = null;
    };
  };
  const socketOnError = (socket, term) => {
    socket.onerror = () => {
      message("连接异常, 请刷新后重试", "error", 3000);
      term.writeln("连接异常, 请刷新后重试");
    };
  };
  // 关闭当前map中的所有websocket
  const closeAll = () => {
    for (var i in webshellMap) {
      const socket = webshellMap[i].socket;
      // 向后端发送关闭请求
      sendCloseMsg(socket);
      socket.close();
    }
  };

  // 向后端发送关闭消息
  const sendCloseMsg = (socket) => {
    const closed = JSON.stringify({
      operation: "closePty",
    });
    socket.send(closed);
  };

  // 关闭map中的socket 并从map中移除该元素
  const CloseByInstanceID = (instanceID) => {
    const socket = webshellMap[instanceID].socket;
    if (socket == undefined || socket == null) {
      message("system error", "error");
      return;
    }
    sendCloseMsg(socket);
    socket.close();
  };

  const SetForcus = (instanceID) => {
    let term = webshellMap[instanceID].term;
    term.focus();
  };

  // 向所有终端发送命令
  const SendAllTerm = (msg = "") => {
    for (var i in webshellMap) {
      const term = webshellMap[i].term;
      const socket = webshellMap[i].socket;
      let msgOrder = {
        operation: "stdin",
        data: msg,
      };
      //发送数据
      socket.send(JSON.stringify(msgOrder));
    }
  };

  return {
    termID,
    setTermID,
    initSocket,
    initTerm,
    closeAll,
    CloseByInstanceID,
    SetForcus,
    SendAllTerm,
    fitListener,
  };
});

export default useWebShell;
